//
// Created by songgf on 25-3-20.
//

#include "BdfToInpConvert.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>


BdfToInpConvert::BdfToInpConvert() {}

BdfToInpConvert::~BdfToInpConvert() {}

int BdfToInpConvert::parseBdfFile(const std::string &path) {
  std::ifstream file(path);
  if (!file) {
    std::cerr << "Error: Cannot open file!" << std::endl;
    return -1;
  }

  std::string line;

  while (std::getline(file, line)) {
    trim(line);
    if (line.empty() || line[0] == '$')
      continue;
  }

  if (line.rfind("GRID", 0) == 0) {
    parseNode(line);
  } else if (line.rfind("CQUAD4", 0) == 0 || line.rfind("CTRIA3", 0) == 0) {
    parseElement(line);
  }

  file.close();
  return 0;
}

void BdfToInpConvert::parseNode(const std::string &line) {
  std::vector<std::string> tokens = split(line, ',');

  if (tokens.size() < 5) {
    return;
  }
  Node node;
  node.id = std::stoi(tokens[1]);
  node.x = std::stoi(tokens[2]);
  node.y = std::stoi(tokens[3]);
  node.z = std::stoi(tokens[4]);

  nodes.push_back(node);
}

void BdfToInpConvert::parseElement(const std::string &line) {
  std::vector<std::string> tokens = split(line, ',');

  if (tokens.size() < 5) {
    return;
  }

  Element element;
  element.id = std::stoi(tokens[1]);
  element.type = mapBdfElementTypeToInp(tokens[0]);

  for (size_t i = 2; i < tokens.size(); i++) {
    element.nodes.push_back(std::stoi(tokens[i]));
  }

  elements.push_back(element);
}

std::string
BdfToInpConvert::mapBdfElementTypeToInp(const std::string &bdfType) {
  static std::map<std::string, std::string> typeMap = {// 四节点壳单元
                                                       {"CQUAD4", "S4"},
                                                       {"CTRIA3", "S3"}};
  return typeMap.count(bdfType) ? typeMap[bdfType] : "UNKNOWN";
}

int BdfToInpConvert::generateInpFil1e(const std::string &path) {
  std::ofstream file(path);
  if (!file.is_open()) {
    std::cerr << "Error opening INP file: " << std::endl;
    return -1;
  }

  file << "*NODE\n";
  for (const auto &node : nodes) {
    file << node.id << ", " << node.x << ", " << node.y << ", " << node.z
         << "\n";
  }

  file << "*ELEMENT, TYPE=" << elements.front().type << "\n";
  for (const auto &element : elements) {
    file << element.id;
    for (int nodeID : element.nodes) {
      file << ", " << nodeID;
    }
    file << "\n";
  }
  file.close();
  return 0;
}

void BdfToInpConvert::trim(std::string &s) {
  s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
            return !std::isspace(ch);
          }));
  s.erase(std::find_if(s.rbegin(), s.rend(),
                       [](unsigned char ch) { return !std::isspace(ch); })
              .base(),
          s.end());
}

std::vector<std::string> BdfToInpConvert::split(const std::string &s,
                                                char delimiter) {
  std::vector<std::string> tokens;
  std::stringstream ss(s);
  std::string token;

  while (std::getline(ss, token, delimiter)) {
    trim(token);
    if (!token.empty())
      tokens.push_back(token);
  }
  return tokens;
}